package close.mazegame.level;

import java.util.Random;

import close.mazegame.tile.Tile;
import close.mazegame.tile.VoidTile;
import close.mazegame.tile.floorTile;
import close.mazegame.tile.WallTile;
import close.mazegame.art.tileset.FloorTileSet;
import close.mazegame.art.tileset.WallTileSet;
import close.mazegame.entity.EndStone;
import close.mazegame.entity.mob.Fleer;
import close.mazegame.entity.mob.Follower;
import close.mazegame.entity.player.Player;
import close.mazegame.entity.player.PlayerAttributes;
import close.util.Maze;

import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Vector2;

public class MazeLevel extends Level {
	
	private static final Random random = new Random();

	public MazeLevel(OrthographicCamera cam, int w, int h) {
		this(cam, w, h, new PlayerAttributes());
	}
	
	public MazeLevel(OrthographicCamera cam, int w, int h, PlayerAttributes pa) {
		super(cam, w, h, pa);
		//rayHandler.setAmbientLight(0.01f);
	}

	protected void createLevel() {
		
		this.wallTileSet = WallTileSet.primary;
		this.floorTileSet = FloorTileSet.primary;

		Maze maze = new Maze(width - 2, height - 2, 20, true);
		
		for (int x = -1; x <= width; x++) {
			for (int y = -1; y <= height; y++) {
				Vector2 pos = new Vector2(x + Tile.SIZE/2, y + Tile.SIZE/2);
				if (x < 0 || x >= width || y < 0 || y >= height) {
					 boundaryTiles.add(new VoidTile(pos, world));
					 continue;
				} else if( x == 0 || y == 0 || x == width - 1 || y == height - 1){
					tiles[x][y] = new WallTile(pos, wallTileSet, world);
					continue;
				}
				int code = maze.getCell(x - 1, y - 1); //Maze (0,0) is at world (1,1) due to the surrounding wall
				
				if (code == Maze.UNEXPOSED) {
					tiles[x][y] = new WallTile(pos, wallTileSet, world);
				} else if (code == Maze.PATH) {
					tiles[x][y] = new floorTile(pos, floorTileSet);
				} else if (code == Maze.WALL) {
					if(random.nextInt(20) == 0){
						tiles[x][y] = new floorTile(pos, floorTileSet);
					} else {
						tiles[x][y] = new WallTile(pos, wallTileSet, world);
					}
				} else if (code == Maze.START) {
					tiles[x][y] = new floorTile(pos, floorTileSet);
					start = new Vector2(x + 0.25f, y + 0.25f);
					
				} else {
					tiles[x][y] = new VoidTile(pos, world);
				}
			}
		}
		setNeighbourMasks();
		pathfinder.setTarget(start);
		pathfinder.update();
		end = new Vector2(pathfinder.getMaxDistancePosition());
	}
	
	@Override
	protected void addEntites() {
		this.add(new EndStone(end, this));
		this.add(new Follower(end, this, pathfinder));
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				if(!tiles[x][y].isSolid()){
					if(random.nextInt(20) == 0){
						this.add(new Fleer( new Vector2(x + Tile.SIZE/2, y + Tile.SIZE/2),this, pathfinder));
					}
				}
			}
		}
	}
	
	@Override
	protected void addPlayer(PlayerAttributes attributes) {
		player = new Player(start, this, attributes);
		pathfinder.setTarget(player.getX(), player.getY());
		pathfinder.update();
	}
	
	private void setNeighbourMasks(){
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				if(tiles[x][y] instanceof WallTile){
					byte mask = getNeighbourMask(x, y);
					((WallTile)tiles[x][y]).setMask(mask);
				}
			}
		}
	}
	
	public byte getNeighbourMask(int x, int y){
		byte mask = 0;
		
		if(isSolid(x - 1, y + 1)){
			mask += 1;
		}
		if(isSolid(x , y + 1)){
			mask += 2;
		}
		if(isSolid(x + 1, y + 1)){
			mask += 4;
		}
		if(isSolid(x + 1, y)){
			mask += 8;
		}
		if(isSolid(x + 1, y - 1)){
			mask += 16;
		}
		if(isSolid(x, y - 1)){
			mask += 32;
		}
		if(isSolid(x - 1, y - 1)){
			mask += 64;
		}
		if(isSolid(x - 1, y)){
			mask += 128; //Overflows the int value of the byte, but that should be fine
		}
		
		return mask;
	}

}
